using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using FluentSilverlight.Expressions.Panels;

namespace FluentSilverlight.Expressions.Grid
{
    public class GridExpression<TModel> : PanelExpression<GridExpression<TModel>, TModel, System.Windows.Controls.Grid>
        where TModel : class 
    {
        private readonly List<ColumnDefinition> gridColumns = new List<ColumnDefinition>();
        private readonly List<RowDefinition> gridRows = new List<RowDefinition>();
        private readonly List<CellItem> children = new List<CellItem>();

        public GridExpression()
        {
        }

        public GridExpression(string name)
            : base(name)
        { }

        public static implicit operator System.Windows.Controls.Grid(GridExpression<TModel> expression)
        {
            var grid = new System.Windows.Controls.Grid();
            expression.BuildUp(grid);
            return grid;
        }

        public GridColumnExpression<GridExpression<TModel>> AddColumn
        {
            get { return new GridColumnExpression<GridExpression<TModel>>(this, gc => gridColumns.Add(gc)); }
        }

        public GridExpression<TModel> PlaceIntoCell(int rowIndex, int columnIndex, FrameworkElement element)
        {
            children.Add(new CellItem(rowIndex, columnIndex, element));
            return thisInstance();
        }

        protected override void BuildUp(System.Windows.Controls.Grid element)
        {
            base.BuildUp(element);

            foreach (var columnDefinition in gridColumns)
                element.ColumnDefinitions.Add(columnDefinition);

            foreach (var rowDefinition in gridRows)
                element.RowDefinitions.Add(rowDefinition);

            foreach (var child in children)
            {
                element.Children.Add(child.Element);
                System.Windows.Controls.Grid.SetColumn(child.Element, child.ColumnIndex);
                System.Windows.Controls.Grid.SetRow(child.Element, child.RowIndex);
            }
        }

        protected override GridExpression<TModel> thisInstance()
        {
            return this;
        }

        private class CellItem
        {
            private readonly int rowIndex;
            private readonly int columnIndex;
            private readonly FrameworkElement element;

            public CellItem(int rowIndex, int columnIndex, FrameworkElement element)
            {
                this.rowIndex = rowIndex;
                this.columnIndex = columnIndex;
                this.element = element;
            }

            public FrameworkElement Element
            {
                get { return element; }
            }

            public int ColumnIndex
            {
                get { return columnIndex; }
            }

            public int RowIndex
            {
                get { return rowIndex; }
            }
        }
    }
}